﻿using Microsoft.EntityFrameworkCore;
using PetAdoptApi.Database;
using PetAdoptApi.Entity;
using PetAdoptApi.Extensions;
using PetAdoptionShared.Dto;
using PetAdoptionShared.Enum;

namespace PetAdoptApi.Endpoints;

public class UserEndpoint
{

    private static readonly SemaphoreSlim semaphore = new(1,1);

    public static void Map(RouteGroupBuilder rgb)
    {
        rgb.MapPost("pet-favorite/toggle/{petId:int}", ToggleUserFavorite);
        rgb.MapGet("pet-favorite/pageable", UserFavoritePetPageableAsync);
        rgb.MapGet("pet-adoption/pageable", UserAdoptionsPageableAsync);
        rgb.MapPost("pet-adoption/adopt/{petId:int}", AdoptPetAsync);
    }

    public static async Task<Res> ToggleUserFavorite(User user, int petId, AppDbContext db)
    {
        var userId = user.Id;
        var userFavorite = await db.UserFavorites.FirstOrDefaultAsync(uf => uf.UserId == userId && uf.PetId == petId);
        if (userFavorite is not null)
        {
            db.UserFavorites.Remove(userFavorite);
        }
        else
        {
            userFavorite = new UserFavorite
            {
                UserId = userId,
                PetId = petId
            };
            await db.UserFavorites.AddAsync(userFavorite);
        }
        _ = db.SaveChangesAsync();
        return Res.Ok();
    }


    public static async Task<Res<PetListDto[]>> UserFavoritePetPageableAsync(User user, [AsParameters] PageableReqDto pageReq, AppDbContext db)
    {
        var userId = user.Id;
        var pets = await db.UserFavorites
            .Where(uf => uf.UserId == userId)
            .Select(uf => uf.Pet).Select(Selectors.PetToPetListDto).ToArrayAsync();
        return Res<PetListDto[]>.Ok(pets);
    }

    public static async Task<Res<PetListDto[]>> UserAdoptionsPageableAsync(User user, [AsParameters] PageableReqDto pageReq, AppDbContext db)
    {
        var userId = user.Id;
        var pets = await db.UserAdoptions
            .Where(ua => ua.UserId == userId)
            .OrderByDescending(ua => ua.Id)
            .Select(ua => ua.Pet).Select(Selectors.PetToPetListDto)
            .ToArrayAsync();
        return Res<PetListDto[]>.Ok(pets);
    }

    public static async Task<Res> AdoptPetAsync(User user,int petId,AppDbContext db)
    {
        var userId = user.Id;
        try
        {
            await semaphore.WaitAsync();
            var pet = await db.Pets
                .AsTracking()
                .FirstOrDefaultAsync(p => p.Id == petId);
            if (pet is null) return Res.Fail("invalid petId");
            if (pet.Status == AdotptionStatus.Adopted) return Res.Fail("already adopted!");

            pet.Status = AdotptionStatus.Adopted;
            var userAdoption = new UserAdoption
            {
                UserId = userId,
                PetId = petId
            };
            await db.UserAdoptions.AddAsync(userAdoption);
            _ = db.SaveChangesAsync();
            return Res.Ok();
        }
        finally { 
            semaphore.Release();
        }
    }
}
